package com.tcm.im.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.base.core.codec.TripleDesUtils;
import com.base.core.exception.ServiceException;
import com.base.core.lang.DateUtils;
import com.base.core.lang.StringUtils;
import com.base.core.utils.JacksonUtils;
import com.base.core.utils.ListUtils;
import com.base.core.utils.R;
import com.base.core.utils.UUIdUtils;
import com.base.genid.generator.UidGenerator;
import com.base.redis.JedisClient;
import com.tcm.doctor.domain.dto.DoctorDTO;
import com.tcm.doctor.service.DoctorService;
import com.tcm.im.dao.mapper.ImChatMapper;
import com.tcm.im.dao.mapper.ImOnlineMapper;
import com.tcm.im.dao.mapper.ImUserFriendsMapper;
import com.tcm.im.dto.*;
import com.tcm.im.entity.ImChat;
import com.tcm.im.entity.ImOnline;
import com.tcm.im.entity.ImUserFriends;
import com.tcm.im.enums.BusinessCodeEnum;
import com.tcm.im.service.HxService;
import com.tcm.im.util.HxUtil;
import com.tcm.ucenter.domain.dto.UserDTO;
import com.tcm.ucenter.service.UserDetailService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@DubboService(version = "0.0.1-alpha", timeout =  3000, retries = 3)
public class HxServiceImpl implements HxService {

    @Autowired
    private HxUtil hxUtil;

    @Autowired
    private JedisClient jedisClient;

    @DubboReference(version = "0.0.1-beta", group = "cached-uid", timeout = 6000, check = false, retries = 3)
    private UidGenerator uidGenerator;

    @DubboReference(version = "0.0.1-alpha", timeout = 6000, check = false, retries = 3)
    private DoctorService doctorService;

    @DubboReference(version = "0.0.1-alpha", timeout = 6000, check = false, retries = 3)
    private UserDetailService userDetailService;

    @Autowired
    private ImOnlineMapper imOnlineMapper;

    @Autowired
    private ImUserFriendsMapper imUserFriendsMapper;

    @Autowired
    private ImChatMapper imChatMapper;

    @Override
    public Token getToken() throws Exception{
        try {
            Token token = hxUtil.getToken();
            //token不存在获取token
            jedisClient.set("token",token.getAccess_token());
            //定义token过期时间
            jedisClient.expire("token",3600 * 24 * 7);
            return token;
        } catch (ServiceException e){
            e.printStackTrace();
            R.throwOnFail(e.getResult());
        }catch (Exception e) {
            e.printStackTrace();
            R.throwFail(e.getMessage());
        }
        return null;
    }

    @Override
    public Boolean addUser(String username) throws Exception {
        //查询用户是否已存在
        String user = hxUtil.queryUser(username);
        if(null != user){
            return true;
        }
        //通过token授权注册用户
        return hxUtil.addUser(username);
    }

    /**
     * 删除用户
     *
     * @param username 用户名
     */
    @Override
    public boolean deleteUser(String username) {
        try {
            return hxUtil.deleteUser(username);
        } catch (Exception e) {
            e.printStackTrace();
            R.throwFail(e.getMessage());
        }
        return false;
    }

    /**
     * 用户端添加好友
     *
     * @param ownerUsername 用户名
     * @param friendName    好友用户名
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean addUserFriend(String ownerUsername, String friendName) throws Exception {

        ImUserFriends imUserFriends = imUserFriendsMapper.findFriends(new Long(ownerUsername), new Long(friendName));
        if(ObjectUtil.isNotEmpty(imUserFriends)){
            return false;
        }

        //正向加好友
        ImUserFriends fans = new ImUserFriends();
        fans.setId(uidGenerator.getUID());
        fans.setCreateTime(DateUtils.nowTime());
        fans.setUid(new Long(ownerUsername));
        fans.setFriendsUid(new Long(friendName));
        fans.setUpdateTime(DateUtils.nowTime());
        fans.setStatus(new Byte("1"));
        imUserFriendsMapper.insert(fans);
        //反向互加好友
        fans.setId(uidGenerator.getUID());
        fans.setUid(new Long(friendName));
        fans.setFriendsUid(new Long(ownerUsername));
        imUserFriendsMapper.insert(fans);
        return true;
    }

    /**
     * 医生端添加好友
     *
     * @param ownerUsername 用户名
     * @param friendName    好友用户名
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean addDoctorFriend(String ownerUsername, String friendName) throws Exception {

        ImUserFriends imUserFriends = imUserFriendsMapper.findFriends(new Long(ownerUsername), new Long(friendName));
        if(ObjectUtil.isNotEmpty(imUserFriends)){
            return false;
        }

        //正向加好友
        ImUserFriends fans = new ImUserFriends();
        fans.setId(uidGenerator.getUID());
        fans.setCreateTime(DateUtils.nowTime());
        fans.setUid(new Long(ownerUsername));
        fans.setFriendsUid(new Long(friendName));
        fans.setUpdateTime(DateUtils.nowTime());
        fans.setStatus(new Byte("1"));
        imUserFriendsMapper.insert(fans);
        //反向互加好友
        fans.setId(uidGenerator.getUID());
        fans.setUid(new Long(friendName));
        fans.setFriendsUid(new Long(ownerUsername));
        imUserFriendsMapper.insert(fans);
        return true;
    }

    /**
     * 我的医生
     * @param ownerUsername
     * @return
     */
    @Override
    public List<ImDoctorFriendsDTO> listFriends(Long ownerUsername){
        List<ImUserFriends> imUserFriendsList = imUserFriendsMapper.listFriends(ownerUsername);
        if(ListUtils.isEmpty(imUserFriendsList)){
            return null;
        }
        List<Long> fuids = new ArrayList<>();
        imUserFriendsList.forEach(imUserFriends -> {
            fuids.add(imUserFriends.getFriendsUid());
        });
        List<DoctorDTO> doctorDTOS = doctorService.listDoctorByUserIds(fuids);
        if(doctorDTOS == null || doctorDTOS.isEmpty()){
            //从表数据为空，直接返回主表数据
            return imUserFriendsList.stream().map(userFriends -> {
                ImDoctorFriendsDTO imDoctorFriendsDTO = new ImDoctorFriendsDTO();
                BeanUtils.copyProperties(userFriends, imDoctorFriendsDTO);
                return imDoctorFriendsDTO;
            }).collect(Collectors.toList());
        }
        //从表集合转换为map
        Map<Long, DoctorDTO> doctorDTOMap = doctorDTOS.stream().collect(Collectors.toMap(
                DoctorDTO::getUserId, doctorDTO->doctorDTO,(oldValue, newValue) -> newValue));
        //left join合并两个list
        List<ImDoctorFriendsDTO> imDoctorFriendsDTOS = imUserFriendsList.stream().map(userFriends -> {
            ImDoctorFriendsDTO imDoctorFriendsDTO = new ImDoctorFriendsDTO();
            BeanUtils.copyProperties(userFriends, imDoctorFriendsDTO);
            if(doctorDTOMap.containsKey(userFriends.getFriendsUid())){
                imDoctorFriendsDTO.setFriendDepartment(doctorDTOMap.get(userFriends.getFriendsUid()).getDepartment());
                imDoctorFriendsDTO.setFriendHospital(doctorDTOMap.get(userFriends.getFriendsUid()).getHospital());
                imDoctorFriendsDTO.setFriendJobtitle(doctorDTOMap.get(userFriends.getFriendsUid()).getJobtitle());
                imDoctorFriendsDTO.setFriendName(doctorDTOMap.get(userFriends.getFriendsUid()).getName());
                imDoctorFriendsDTO.setFriendAvatar(doctorDTOMap.get(userFriends.getFriendsUid()).getAvatar());
            }
            return imDoctorFriendsDTO;
        }).collect(Collectors.toList());
        return imDoctorFriendsDTOS;
    }

    /**
     * 我的患者
     * @param ownerUsername
     * @return
     */
    @Override
    public List<ImUserFriendsDTO> listUserFriends(Long ownerUsername){
        List<ImUserFriends> imUserFriendsList = imUserFriendsMapper.listFriends(ownerUsername);
        if(ListUtils.isEmpty(imUserFriendsList)){
            return null;
        }
        List<Long> fuids = new ArrayList<>();
        imUserFriendsList.forEach(imUserFriends -> {
            fuids.add(imUserFriends.getFriendsUid());
        });
        List<UserDTO> userDTOS = userDetailService.listUserByUserIds(fuids);
        if(userDTOS == null || userDTOS.isEmpty()){
            //从表数据为空，直接返回主表数据
            return imUserFriendsList.stream().map(user -> {
                ImUserFriendsDTO userFriendsDTO = new ImUserFriendsDTO();
                BeanUtils.copyProperties(user, userFriendsDTO);
                return userFriendsDTO;
            }).collect(Collectors.toList());
        }
        //从表集合转换为map
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(
                UserDTO::getUserId, userDTO->userDTO,(oldValue, newValue) -> newValue));
        //left join合并两个list
        List<ImUserFriendsDTO> imUserFriendsDTOS = imUserFriendsList.stream().map(userFriends -> {
            ImUserFriendsDTO imUserFriendsDTO = new ImUserFriendsDTO();
            BeanUtils.copyProperties(userFriends, imUserFriendsDTO);
            if(userDTOMap.containsKey(userFriends.getFriendsUid())){
                imUserFriendsDTO.setFriendSex(userDTOMap.get(userFriends.getFriendsUid()).getSex().toString());
                imUserFriendsDTO.setFriendMobile(userDTOMap.get(userFriends.getFriendsUid()).getMobile());
                imUserFriendsDTO.setFriendsUid(userDTOMap.get(userFriends.getFriendsUid()).getUserId());
                imUserFriendsDTO.setFriendName(userDTOMap.get(userFriends.getFriendsUid()).getRealname());
                imUserFriendsDTO.setFriendAvatar(userDTOMap.get(userFriends.getFriendsUid()).getAvatar());
                imUserFriendsDTO.setCreateTime(userDTOMap.get(userFriends.getFriendsUid()).getCreateTime());
            }
            return imUserFriendsDTO;
        }).collect(Collectors.toList());
        return imUserFriendsDTOS;
    }

    /**
     * 医生端查询好友会话列表
     * @param ownerUsername
     * @return
     */
    @Override
    public List<ImChatDTO> listFriendsOnlineForDoctor(Long ownerUsername) throws Exception{
        List<ImChat> imChatList = imChatMapper.listOnline(ownerUsername);
        if(ListUtils.isEmpty(imChatList)){
            return null;
        }
        List<Long> uids = new ArrayList<>();
        imChatList.forEach(imUserFriends -> {
            uids.add(imUserFriends.getToId());
        });
        List<UserDTO> userDTOS = userDetailService.listUserByUserIds(uids);
        if(userDTOS == null || userDTOS.isEmpty()){
            //从表数据为空，直接返回主表数据
            return imChatList.stream().map(imChat -> {
                ImChatDTO imChatDTO = new ImChatDTO();
                BeanUtils.copyProperties(imChat, imChatDTO);
                return imChatDTO;
            }).collect(Collectors.toList());
        }
        //从表集合转换为map
        Map<Long, UserDTO> userDTOMap = userDTOS.stream().collect(Collectors.toMap(
                UserDTO::getUserId, userDTO->userDTO,(oldValue, newValue) -> newValue));
        //left join合并两个list
        List<ImChatDTO> imChatDTOS = imChatList.stream().map(imChat -> {
            ImChatDTO imChatDTO = new ImChatDTO();
            BeanUtils.copyProperties(imChat, imChatDTO);
            if(userDTOMap.containsKey(imChat.getToId())){
                imChatDTO.setChatAvatar(userDTOMap.get(imChat.getToId()).getAvatar());
                imChatDTO.setChatName(userDTOMap.get(imChat.getToId()).getRealname());
            }
            return imChatDTO;
        }).collect(Collectors.toList());
        return imChatDTOS;
    }

    /**
     * 用户端好友接口
     * @param ownerUsername
     * @return
     */
    @Override
    public List<ImChatDTO> listFriendsOnlineForUser(Long ownerUsername){
        List<ImChat> imChatList = imChatMapper.listOnline(ownerUsername);
        if(ListUtils.isEmpty(imChatList)){
            return null;
        }
        List<Long> fuids = new ArrayList<>();
        imChatList.forEach(imUserFriends -> {
            fuids.add(imUserFriends.getToId());
        });
        List<DoctorDTO> doctorDTOS = doctorService.listDoctorByUserIds(fuids);
        if(doctorDTOS == null || doctorDTOS.isEmpty()){
            //从表数据为空，直接返回主表数据
            return imChatList.stream().map(imChat -> {
                ImChatDTO imChatDTO = new ImChatDTO();
                BeanUtils.copyProperties(imChat, imChatDTO);
                return imChatDTO;
            }).collect(Collectors.toList());
        }
        //从表集合转换为map
        Map<Long, DoctorDTO> doctorDTOMap = doctorDTOS.stream().collect(Collectors.toMap(
                DoctorDTO::getUserId, doctorDTO->doctorDTO,(oldValue, newValue) -> newValue));
        //left join合并两个list
        List<ImChatDTO> imChatDTOS = imChatList.stream().map(imChat -> {
            ImChatDTO imChatDTO = new ImChatDTO();
            BeanUtils.copyProperties(imChat, imChatDTO);
            if(doctorDTOMap.containsKey(imChat.getToId())){
                imChatDTO.setDepartment(doctorDTOMap.get(imChat.getToId()).getDepartment());
                imChatDTO.setHospital(doctorDTOMap.get(imChat.getToId()).getHospital());
                imChatDTO.setJobtitle(doctorDTOMap.get(imChat.getToId()).getJobtitle());
                imChatDTO.setChatName(doctorDTOMap.get(imChat.getToId()).getName());
                imChatDTO.setChatAvatar(doctorDTOMap.get(imChat.getToId()).getAvatar());
            }
            return imChatDTO;
        }).collect(Collectors.toList());
        return imChatDTOS;
    }

    /**
     * 删除好友
     *
     * @param ownerUsername 用户名
     * @param friendName    好友用户名
     * @return 是否成功
     */
    @Transactional
    @Override
    public boolean deleteFriend(String ownerUsername, String friendName) throws Exception {
        try {
            Boolean rs = hxUtil.deleteFriend(ownerUsername, friendName);
            if(rs){
                imUserFriendsMapper.deleteFriend(new Long(ownerUsername), new Long(friendName));
                imUserFriendsMapper.deleteFriend(new Long(friendName), new Long(ownerUsername));
            }
        } catch (ServiceException e) {
            e.printStackTrace();
            R.throwOnFail(e.getResult());
        } catch (Exception e) {
            e.printStackTrace();
            R.throwFail(e.getMessage());
        }
        return true;
    }

    /**
     * 发送消息
     *
     * @param imChatDTO 发送消息
     * @return 是否成功
     */
    @Transactional
    @Override
    public String saveSessionData(ImChatDTO imChatDTO) throws ServiceException {
        String chatId = null;
        try{
            if(ObjectUtil.isEmpty(imChatDTO.getFromId())){
                R.throwFail(BusinessCodeEnum.SENDER_NOT_FOUND);
            }

            if(ObjectUtil.isEmpty(imChatDTO.getConsultationId())){
                R.throwFail(BusinessCodeEnum.CONSULTATIONID_NOT_FOUND);
            }
            //true为患者向医生发送消息，否则false为医生向患者发送消息
            Boolean direction = imChatDTO.getDireaction();
            //初始化会话
            ImOnlineDTO imOnlineDTO = new ImOnlineDTO();
            imOnlineDTO.setChatId(imChatDTO.getChatId());
            imOnlineDTO.setFromId(imChatDTO.getFromId());
            imOnlineDTO.setToId(imChatDTO.getToId());
            chatId = createSession(imOnlineDTO, direction);
            ImChat imChat = new ImChat();
            //更新会话表
            imChat.setLastMessage(imChatDTO.getLastMessage());
            imChat.setLastUserName(imChatDTO.getChatName());
            imChat.setStatus(new Byte("1"));
            imChat.setChatId(chatId);
            imChat.setUpdateTime(DateUtils.nowTime());
            imChat = imChatMapper.findOnlineByChatId(imChatDTO.getFromId(),chatId);
            if(ObjectUtil.isNotEmpty(imChat)){
                imChat.setFromId(imChatDTO.getFromId());
                imChatMapper.update(imChat);
                //反向
                imChat.setFromId(imChatDTO.getToId());
                imChatMapper.update(imChat);
            }else {
                //新增会话
                imChat = new ImChat();
                BeanUtils.copyProperties(imChatDTO, imChat);
                imChat.setId(uidGenerator.getUID());
                imChat.setChatId(chatId);
                imChat.setCreateTime(DateUtils.nowTime());
                imChat.setUpdateTime(DateUtils.nowTime());
                imChat.setLastUserName(imChatDTO.getChatName());
                imChatMapper.insert(imChat);
                //反向
                imChat.setFromId(imChatDTO.getToId());
                imChat.setToId(imChatDTO.getFromId());
                imChat.setId(uidGenerator.getUID());
                imChatMapper.insert(imChat);
            }
        }catch (ServiceException e) {
            e.printStackTrace();
            R.throwOnFail(e.getResult());
        } catch (Exception e) {
            e.printStackTrace();
            R.throwFail(e.getMessage());
        }
        return chatId;
    }

    /**
     * 创建会话
     *
     * @param onlineDTO        发送消息
     * @param direction true为患者向医生发送消息，否则false为医生向患者发送消息
     * @return 是否成功
     */
    @Transactional
    @Override
    public String createSession(ImOnlineDTO onlineDTO, Boolean direction) throws ServiceException{
        try{
            if(ObjectUtil.isEmpty(onlineDTO.getFromId())){
                R.throwFail(BusinessCodeEnum.SENDER_NOT_FOUND);
            }
            ImOnline imOnline;
            if(direction){
                //从患者到医生方向
                imOnline = imOnlineMapper.selectOnline(onlineDTO.getFromId(), onlineDTO.getToId());
            }else {
                //从医生到患者方向
                imOnline = imOnlineMapper.selectOnline(onlineDTO.getToId(), onlineDTO.getFromId());
            }

            if(ObjectUtil.isNotEmpty(imOnline)){
                //更新会话表
                imOnline.setUpdateTime(DateUtils.nowTime());
                imOnlineMapper.update(imOnline);
            }else{
              imOnline = new ImOnline();
              BeanUtils.copyProperties(onlineDTO, imOnline);
              imOnline.setId(uidGenerator.getUID());
              imOnline.setUpdateTime(DateUtils.nowTime());
              imOnline.setCreateTime(DateUtils.nowTime());
              imOnline.setChatId(UUIdUtils.fastUUID());
              imOnlineMapper.insert(imOnline);
            }
            return imOnline.getChatId();
       }catch (ServiceException e) {
           e.printStackTrace();
           R.throwOnFail(e.getResult());
       } catch (Exception e) {
           e.printStackTrace();
           R.throwFail(e.getMessage());
       }
       return null;
    }


    /**
     * 保存医患关系
     * @param param 加密的参数
     */
    @Override
    public boolean saveDoctorPatient(String param) throws ServiceException {
        boolean result = false;
        try {
            if(StringUtils.isEmpty(param)){
                return result;
            }
            String decodeParam = URLDecoder.decode(param,"utf8");
            String[] paramList = decodeParam.split("\\|");
            String urlcode = URLDecoder.decode(paramList[0], "utf8");
            String secretDoctorUser = TripleDesUtils.decrypt(urlcode.substring(10, urlcode.length())
                    .replaceAll(" ", "+"), "1234123sdu9du");
            if (null != secretDoctorUser && paramList[1] != null) {
                String userId = paramList[1];
                String doctorUser = secretDoctorUser.substring(0, secretDoctorUser.indexOf("@"));
                Map doctor = JacksonUtils.toMap(doctorUser);
                doctorUser = (String)doctor.get("doctorUserId");
                //查询用户id
                UserDTO userDTO = userDetailService.findUserByUserId(new Long(userId));
                if(userDTO != null){
                    result = addUserFriend(userId, doctorUser);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            result = false;
        }
        return result;
    }



}
